package com.big.codegen.service.impl;

import cn.hutool.core.text.CharSequenceUtil;
import com.big.codegen.domain.dto.CodeGenServiceDTO;
import com.big.codegen.domain.dto.CodegenTableConfigDTO;
import com.big.codegen.service.CodegenService;
import com.big.common.core.exception.CustomerException;
import com.google.common.collect.Maps;
import freemarker.template.Configuration;
import freemarker.template.Template;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.ByteArrayOutputStream;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * <p>
 * 代码生成服务实现类
 * </p>
 *
 * @author 山归岿
 * @create 2025-06-25-21:42
 */
@Slf4j
@Service
public class CodegenServiceImpl implements CodegenService {

    private final Configuration freemarkerConfig;

    public CodegenServiceImpl(@Qualifier("codegenFreemarkerConfiguration") Configuration freemarkerConfig) {
        this.freemarkerConfig = freemarkerConfig;
    }

    @Override
    public ResponseEntity<Resource> downloadCodeZip(CodegenTableConfigDTO config) {
        return null;
    }

    @Override
    public ResponseEntity<Resource> downloadService(CodeGenServiceDTO config, HttpServletResponse response) {
        try {
            // 参数校验
            validateCodegenConfig(config);

            // 生成代码并打包成字节数组
            byte[] zipBytes = generateCodeZipBytes(config);

            // 创建资源
            ByteArrayResource resource = new ByteArrayResource(zipBytes);

            // 设置响应头
            String fileName = (config.getModuleName() != null ? config.getModuleName() : "generated-code") + ".zip";

            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"")
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .contentLength(zipBytes.length)
                    .body(resource);

        } catch (CustomerException e) {
            log.error("代码生成失败: {}", e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("代码生成失败", e);
            throw new CustomerException("代码生成失败: " + e.getMessage());
        }
    }

    /**
     * 参数校验 - CodegenTableConfigDTO
     */
    private void validateCodegenConfig(CodeGenServiceDTO config) {
        if (config == null) {
            throw new CustomerException("配置信息不能为空");
        }
        if (!StringUtils.hasText(config.getModuleName())) {
            throw new CustomerException("模块名称不能为空");
        }
        if (!StringUtils.hasText(config.getModuleDescription())) {
            throw new CustomerException("模块描述不能为空");
        }
    }

    /**
     * 生成代码并返回字节数组
     */
    private byte[] generateCodeZipBytes(CodeGenServiceDTO config) throws Exception {
        try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
             ZipOutputStream zipOut = new ZipOutputStream(byteArrayOutputStream, StandardCharsets.UTF_8)) {

            // 准备模板数据
            Map<String, Object> dataModel = prepareCodegenDataModel(config);

            // 生成父模块pom.xml
            generateFile(zipOut, "service/pom.xml.ftl", config.getModuleName() + "/pom.xml", dataModel);

            // 生成biz模块pom.xml
            generateFile(zipOut, "service/biz-pom.xml.ftl",
                    config.getModuleName() + "/" + config.getModuleName() + "-biz/pom.xml", dataModel);

            // 生成api模块pom.xml
            generateFile(zipOut, "service/api-pom.xml.ftl",
                    config.getModuleName() + "/" + config.getModuleName() + "-api/pom.xml", dataModel);

            // 生成启动类
            String packagePath = "com/big/" + config.getModuleName() + "/biz";
            String bizJavaPath = config.getModuleName() + "/" + config.getModuleName() + "-biz/src/main/java/" + packagePath + "/";
            String applicationPath = config.getModuleName() + "/" + config.getModuleName() + "-biz/src/main/java/" + packagePath + "/" +
                    CharSequenceUtil.upperFirst(config.getModuleName()) + "Application.java";
            generateFile(zipOut, "service/Application.java.ftl", applicationPath, dataModel);

            // 生成biz模块配置文件
            String bizBootstrapPath = config.getModuleName() + "/" + config.getModuleName() + "-biz/src/main/resources/bootstrap.yml";
            generateFile(zipOut, "service/biz-bootstrap.yml.ftl", bizBootstrapPath, dataModel);

            // 创建api模块文件夹结构
            String apiPackagePath = "com/big/" + config.getModuleName() + "/api";
            String apiJavaPath = config.getModuleName() + "/" + config.getModuleName() + "-api/src/main/java/" + apiPackagePath + "/";
            String apiResourcesPath = config.getModuleName() + "/" + config.getModuleName() + "-api/src/main/resources/";

            // 创建biz模块的文件夹结构
            createDirectory(zipOut, bizJavaPath + "entity/");
            createDirectory(zipOut, bizJavaPath + "dto/");
            createDirectory(zipOut, bizJavaPath + "vo/");
            createDirectory(zipOut, bizJavaPath + "service/");
            createDirectory(zipOut, bizJavaPath + "mapper/");
            createDirectory(zipOut, config.getModuleName() + "/" + config.getModuleName() + "-biz/src/main/resources/");
            
            // 创建api模块的文件夹结构
            createDirectory(zipOut, apiJavaPath + "entity/");
            createDirectory(zipOut, apiJavaPath + "dto/");
            createDirectory(zipOut, apiJavaPath + "vo/");
            createDirectory(zipOut, apiJavaPath + "service/");
            createDirectory(zipOut, apiJavaPath + "mapper/");
            createDirectory(zipOut, apiJavaPath + "feign/");
            createDirectory(zipOut, apiResourcesPath);

            zipOut.finish();
            return byteArrayOutputStream.toByteArray();
        }
    }

    /**
     * 准备模板数据 - CodegenTableConfigDTO
     */
    private Map<String, Object> prepareCodegenDataModel(CodeGenServiceDTO config) {
        Map<String, Object> dataModel = Maps.newHashMap();
        dataModel.put("moduleName", config.getModuleName());
        dataModel.put("moduleDescription", config.getModuleDescription());
        dataModel.put("className", CharSequenceUtil.upperFirst(config.getModuleName()));
        dataModel.put("author", "山归岿");
        dataModel.put("createTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd-HH:mm")));
        return dataModel;
    }


    /**
     * 生成单个文件
     */
    private void generateFile(ZipOutputStream zipOut, String templateName, String fileName, Map<String, Object> dataModel) throws Exception {
        // 获取模板
        Template template = freemarkerConfig.getTemplate(templateName);

        // 创建ZIP条目
        ZipEntry zipEntry = new ZipEntry(fileName);
        zipOut.putNextEntry(zipEntry);

        // 生成内容并写入ZIP
        try (StringWriter stringWriter = new StringWriter()) {
            template.process(dataModel, stringWriter);
            zipOut.write(stringWriter.toString().getBytes(StandardCharsets.UTF_8));
        }

        zipOut.closeEntry();
    }

    /**
     * 创建文件夹
     */
    private void createDirectory(ZipOutputStream zipOut, String dirPath) throws Exception {
        // 确保路径以斜杠结尾
        if (!dirPath.endsWith("/")) {
            dirPath += "/";
        }
        ZipEntry zipEntry = new ZipEntry(dirPath);
        zipOut.putNextEntry(zipEntry);
        zipOut.closeEntry();
    }

}
